﻿/************************************************
 * Author       :   XXY
 * Blog         :   https://www.cnblogs.com/jzyl
 * Gitee        :   https://gitee.com/xiaobaichong
 * Email        :   1047185209@QQ.com
 * FileName     :   Delayer.cs
 * CreateData   :   2024/8/13 23:34:39
 * UnityVersion :   2022.3.2t15
 * Description  :   延迟执行器
************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Main
{
    /// <summary>
    /// 延迟执行器
    /// </summary>
    public class Delayer : SingletonMono<Delayer>
    {
        private List<string> DumpTags = new List<string>(10);                                                               // 空 标签
        private Dictionary<string, List<(Action, float)>> SecondDic = new Dictionary<string, List<(Action, float)>>();      // 秒时间 事件 
        private Dictionary<string, List<(Action, int)>> FrameDic = new Dictionary<string, List<(Action, int)>>();           // 帧时间 事件
        private void Update()
        {
            // 秒 Tick
            DumpTags.Clear();
            foreach (var SecondEvent in SecondDic)
            {
                var list = SecondEvent.Value;
                for (int i = 0; i < list.Count;)
                {
                    var t = list[i];
                    t.Item2 -= Time.deltaTime;
                    if (t.Item2 <= 0)
                    {
                        list.RemoveAt(i);
                        t.Item1?.Invoke();
                    }
                    else
                    {
                        list[i] = t;
                        i++;
                    }
                }
                if (list.Count == 0) DumpTags.Add(SecondEvent.Key);
            }
            foreach (var item in DumpTags)
            {
                SecondDic.Remove(item);
            }

            // 帧 Tick
            DumpTags.Clear();
            foreach (var FrameEvent in FrameDic)
            {
                var list = FrameEvent.Value;
                for (int i = 0; i < list.Count;)
                {
                    var t = list[i];
                    t.Item2 -= 1;
                    if (t.Item2 <= 0)
                    {
                        list.RemoveAt(i);
                        t.Item1?.Invoke();
                    }
                    else
                    {
                        list[i] = t;
                        i++;
                    }
                }
                if (list.Count == 0) DumpTags.Add(FrameEvent.Key);
            }
            foreach (var item in DumpTags)
            {
                FrameDic.Remove(item);
            }
        }
        /// <summary>
        /// 延迟多少秒开始触发
        /// </summary>
        /// <param name="work">延迟执行</param>
        /// <param name="second">多少秒</param>
        /// <param name="tag">标签</param>
        public void DelaySecond(Action work, float second, string tag = "")
        {
            if (!SecondDic.ContainsKey(tag))
            {
                SecondDic[tag] = new List<(Action, float)>();
            }
            SecondDic[tag].Add((work, second));
        }
        /// <summary>
        /// 延迟多少帧开始触发
        /// </summary>
        /// <param name="work">延迟执行</param>
        /// <param name="second">多少帧</param>
        /// <param name="tag">标签</param>
        public void DelayFrame(Action work, int frame, string tag = "")
        {
            if (!FrameDic.ContainsKey(tag))
            {
                FrameDic[tag] = new List<(Action, int)>();
            }
            FrameDic[tag].Add((work, frame));
        }
        /// <summary>
        /// 移除但不会触发指定标签内的 所有事件
        /// </summary>
        public void Off(string tag)
        {
            SecondDic.Remove(tag);
            FrameDic.Remove(tag);
        }
        /// <summary>
        /// 立刻触发并移除指点标签内的 所有事件
        /// </summary>
        /// <param name="tag"></param>
        public void Emit(string tag)
        {
            if (SecondDic.ContainsKey(tag))
            {
                foreach (var item in SecondDic[tag])
                {
                    item.Item1?.Invoke();
                }
            }
            if (FrameDic.ContainsKey(tag))
            {
                foreach (var item in FrameDic[tag])
                {
                    item.Item1?.Invoke();
                }
            }
            Off(tag);
        }
    }
}